#include "calc.h"


void calc::check(){
	try {
		uptolow();
#ifndef NDEBUG
		cout << "uptolow:" << convstr << endl;
#endif
		if (!checkSym()) {
			throw sfError(MORE_SYM, "more symbol");
		}
		convent();
#ifndef NDEBUG
		cout << "convert:" << convstr << endl;
#endif
		if (!bracket_match()) {
			throw sfError(BRACKET_MATCH, "bracket match error");
		}
		addjc();
#ifndef NDEBUG
		cout << "addjc:" << convstr << endl;
#endif
		if (!char_match()) {
			throw sfError(CHAR_MATCH, "char match error");
		}
		if (!arg_num_match()) {
			throw sfError(ARG_NUM_MATCH, "args number match error");
		}
	} catch (...) {
		throw;
	}
}



bool calc::checkSym(){
	try {
		string temp(convstr);
		int pos;
		for (vector<string>::iterator p = repsort.begin(); p != repsort.end(); ++p) {
			pos = temp.size();
			while ((pos = temp.rfind(*p), pos) != string::npos) {
				temp.erase(pos, p->size());
			}
		}
		for (string::iterator p = temp.begin(); p != temp.end(); ++p) {
			if (*p >= '0'&&*p <= '9') {
				continue;
			}
			switch (*p) {
			case '.':case '(':case ')':case ',':
				break;
			default:
				return false;
			}
		}
		return true;
	} catch (...) {
		throw;
	}
}

void calc::uptolow(){
	try {
		//upper to lower and delete blank
		for (string::iterator p = sourceStr.begin(); p != sourceStr.end(); ++p) {
			if (isspace(*p)) {
				continue;
			}
			convstr.push_back(tolower(*p));
		}
	} catch(...){
		throw;
	}
}


bool calc::bracket_match(){
	try {
		int num(0);
		for (string::iterator p = convstr.begin(); p != convstr.end(); ++p) {
			switch (*p) {
			case '(':
				++num;
				break;
			case ')':
				--num;
			default:
				break;
			}
		}
		return num == 0;
	} catch (...) {
		throw;
	}
}


void calc::convent(){
	try {
		int pos;
		for (vector<string>::iterator p = repsort.begin(); p != repsort.end(); ++p) {
			pos = convstr.size();
			while ((pos = convstr.rfind(*p, pos)) != string::npos) {
				convstr.erase(pos, p->size());
				convstr.insert(convstr.begin() + pos, maprep[*p].begin(), maprep[*p].end());
				--pos;
			}
		}
	} catch(...){
		throw;
	}
}


void calc::addjc(){
	try {
		int pos = convstr.size();
		while ((pos = convstr.rfind('!', pos)) != string::npos) {
			convstr.insert(convstr.begin() + pos + 1, '0');
			--pos;
		}
		convstr.insert(convstr.begin(), '#');
		convstr.push_back('#');
	} catch(...){
		throw;
	}
}

bool calc::char_match(){
	try {
		bool point(false);
		char bf('#');
		char no('#');
		for (string::iterator p = convstr.begin() + 1; p != convstr.end(); ++p) {
			if (*p <= '9'&&*p >= '0') {
				bf = no;
				no = 'n';
			} else {
				for (vector<string>::iterator q = shortSym.begin(); q != shortSym.end(); ++q) {
					if (*p == (*q)[0]) {
						point = false;
						bf = no;
						no = 's';
						goto lab1;
					}
				}
				switch (*p) {
				case '+':
					point = false;
					bf = no;
					no = '+';
					break;
				case '-':
					point = false;
					bf = no;
					no = '-';
					break;

				case '*':
				case '/':
				case '%':
				case 'e':
				case '!':
				case '^':
					point = false;
					bf = no;
					no = 'd';
					break;
				case '(':
					point = false;
					bf = no;
					no = '(';
					break;
				case ')':
					point = false;
					bf = no;
					no = ')';
					break;
				case '.':
					if (point) {
						return false;
					}
					point = true;
					bf = no;
					no = '.';
					break;
				case ',':
					point = false;
					bf = no;
					no = ',';
					break;
				case '#':
					point = false;
					bf = no;
					no = '#';
					break;
				default:
					return false;
				}
			}
		lab1:
			if (errgrp[make_pair(bf, no)]) {
				return false;
			}
		}
		return true;
	} catch (...) {
		throw;
	}
}


bool calc::arg_num_match(){
	try {
		int pos;
		vector<string> temp;
		for (vector<string>::iterator p = shortSym.begin(); p != shortSym.end(); ++p) {
			pos = 0;
			int t;
			while ((pos = convstr.find(*p, pos)) != string::npos) {
				++pos;
				if (argNum[*p] >= 0) {
					if (getArgc(pos, convstr, temp, t) != argNum[*p]) {
						return false;
					}
				} else {
					if (getArgc(pos, convstr, temp, t) < -argNum[*p]) {
						return false;
					}
				}
			}
		}
		return true;
	} catch(...){
		throw;
	}
}


int calc::getArgc(int pos, string convstr,vector<string>& args,int &t){
	try {
		args.clear();
#ifndef NDEBUG
		cout << "args div:" << endl;
#endif
		int brac(0);
		string temp;
		for (int i = pos + 1; i < convstr.size(); ++i) {
			switch (convstr[i]) {
			case '(':
				++brac;
				temp.push_back('(');
				break;
			case ')':
				--brac;
				if (brac == -1) {
					if (!temp.empty()) {
						args.push_back(temp);
					}
					t = i - pos;
#ifndef NDEBUG
					cout << temp << endl;
#endif
					return args.size();
				}
				temp.push_back(')');
				break;
			case ',':
				if (brac == 0) {
					args.push_back(temp);
					temp.clear();
				}
#ifndef NDEBUG
				cout << temp << endl;
#endif
				
				break;
			default:
				temp.push_back(convstr[i]);
				break;
			}
		}
		throw sfError(OTHER_ERROR, "other error");
	} catch (...) {
		throw;
	}
}